package cn.edu.java.collection;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.*;

public class MyHashMapDemo<K, V> {

    // 基于数组和琏表
    private Node<K, V>[] table;

    float loadFactor;
    private int threshold;
    int size;

    public MyHashMapDemo() {
        table = (Node<K, V>[])new Node[16];
        this.loadFactor = 0.75F;
        this.threshold = (int) (table.length * loadFactor);
        this.size = 0;
    }


    Node<K, V> newNode(K key, V value) {
        return new Node<>(key, value, null);
    }

    @Data
    @AllArgsConstructor
    static class Node<K, V> {
        K key;
        V value;
        Node<K, V> next;
    }


    public V put(K key, V value) {
        if (size >= threshold) {
            resize();
        }
        int hash = key == null ? 0 : key.hashCode();
        return putval(hash, key, value);
    }

    private V putval(int hash, K key, V value) {
        int length = table.length;
        int i = hash % length;
        Node<K, V> node = newNode(key, value);
        if (table[i] == null) {
            table[i] = node;
            size++;
            return null;
        }
        for (Node<K, V> p = table[i]; p != null; p = p.next) {
            if (Objects.equals(node.key, p.key)) {
                V oldvalue = p.value;
                p.value = node.value;
                return oldvalue;
            }
        }
        node.next = table[i];
        table[i] = node;
        size++;

        return null;
    }

    private void resize() {
        int newLength = table.length << 1; // double
        this.threshold = threshold << 1; // double
        Node<K, V>[] oldtable = this.table;
        this.table = (Node<K, V>[])new Node[newLength];
        for (Node<K, V> node : oldtable) {
            while (node != null) {
                this.put(node.key, node.value);
                node = node.next;
            }
        }
    }

    public V get(K key) {
        int hash = key == null ? 0 : key.hashCode();
        int i = hash % table.length;
        Node<K, V> node = table[i];
        while (node != null) {
            if (node.key.equals(key)) return node.value;
            node = node.next;
        }
        return null;
    }


    public static void main(String[] args) {
        MyHashMapDemo<String, String> myHashMap = new MyHashMapDemo<>();
        myHashMap.put("123", "45");
        System.out.println(myHashMap.get("123"));

        for (int i = 0; i < 10000; i++) {
            myHashMap.put(i + "", i + "");
        }

        for (int i = 0; i < 10001; i++) {
            System.out.println(myHashMap.get(i + ""));
        }

    }


}
